<template>
	<view class="content">
		<view class="container">
			<view class="identify-text">{{result}}</view>
			<view class="identify-btn-media">
				<view class="identify-btn-box active">
					<view class="loading" v-if="recording">
						<view class="line1"></view>
						<view class="line3"></view>
						<view class="line2"></view>
						<view class="line4"></view>
						<view class="line5"></view>
						<view class="line3"></view>
						<view class="line4"></view>
						<view class="line1"></view>
						<view class="line2"></view>
					</view>
					<view class="loading" v-if="recording">
						<view class="line1"></view>
						<view class="line3"></view>
						<view class="line2"></view>
						<view class="line4"></view>
						<view class="line5"></view>
						<view class="line3"></view>
						<view class="line4"></view>
						<view class="line1"></view>
						<view class="line2"></view>
					</view>
				</view>
				<view>
					<view @click='startLy()' class="btn btn-start" v-if="!recording">
						开始识别
					</view>
					<view @click='endLy()' class="btn btn-end" v-if="recording">
						停止识别
					</view>
				</view>


				<view>
					<button @click="playAudio1">播放音频</button>
					<button @click="playAudio2">播放暂停</button>
					<button @click="playAudio3">播放停止1</button>
				</view>

				<view>
					<button @click="fnChecking">识别判断</button>
					<view class="tableHeader" v-for="(item,index) in tableList" :key="index">
						<view style="width:60px">
							{{item.id}}
						</view>
						<view style="flex:1">
							{{item.content}}
						</view>
						<view style="width:60px">
							{{item.voice_id}}
						</view>
					</view>
				</view>
			</view>
		</view>

	</view>
</template>

<script>
	import $fnTxvoice from '../../request/fnTxvoice.js'
	const plugin = requirePlugin("QCloudAIVoice");
	let keyword = 'apple';
	let keyword_split = keyword.split("").join(" ");
	let voice_id = null; //实时语音实别实例id
	let isCanStop = true;
	let wordTip = ["pardon", "repeat", "again", "pronunciation", "word", "world"];
	let speechTip = ["part of speech", "part", "part speech", "part of", "of speech", "speech"];
	let definitionTip = ["definition", "define", "definite", "dolphin", "deafening", "defi", "defeat", " da.", ".da"];
	let sentenceTip = ["sentence", "certain", "Cent", "Heaven", "Part of which"];
	let tipObj = {
		word: wordTip,
		part_of_speech: speechTip,
		definition: definitionTip,
		sentence: sentenceTip,
	};


	let resultText = '';
	export default {
		data() {
			return {
				socket: null,
				speechRecognizerManager: null,
				isCanSendData: false,
				result: '',
				res: '',
				recording: false,
				disabled: false,
				isRecognizeStop: false,
				recognizeResult: '',

				audioSrc: 'https://cdn.spbcn.org/audio/lexicon/0/sky3.mp3', // 音频文件地址
				isPlaying: false, // 是否正在播放

				tableList: [{
					id: 'a',
					content: '21',
					voice_id: '1'
				}],
			}
		},
		onLoad() {


			if ('初始化音频事件') {
				this.initAudioEvent()
			}


			if ('语音识别') {
				this.speechRecognizerManager = plugin.speechRecognizerManager();

				// 开始识别
				this.speechRecognizerManager.OnRecognitionStart = (res) => {
					console.log('开始识别', res);
					voice_id = res.voice_id;
					this.isCanSendData = true;

					this.recording = true;
					this.disabled = true;
					this.result = '';
				};
				// 一句话开始
				this.speechRecognizerManager.OnSentenceBegin = (res) => {
					console.log('一句话开始', res);
					isCanStop = true;
				};
				// 识别变化时
				this.speechRecognizerManager.OnRecognitionResultChange = (res) => {
					console.log('识别变化时', res);
					if (voice_id == res.voice_id) {
						this.result = `${resultText || ''}${res.result.voice_text_str}`;
						//核验结果【简单：过滤错误的情况，仅当对的时候提示答题成功】
						this.fnCheckResultSimple(this.result, keyword);
					}
				};
				// 一句话结束
				this.speechRecognizerManager.OnSentenceEnd = (res) => {
					console.log('一句话结束', res);
					resultText += res.result.voice_text_str;


					if (voice_id == res.voice_id) {
						resultText += res.result.voice_text_str;
						this.result = resultText

						uni.showLoading({
							title: '一句话结束',
							mask: true,
						})

						//TODO 核验结果
						this.fnCheckResult(resultText, keyword);
					}
				};
				// 识别结束
				this.speechRecognizerManager.OnRecognitionComplete = (res) => {
					console.log('识别结束', res);
					this.isRecognizeStop = true;
					this.recording = false;
					this.disabled = false;
				};
				// 识别错误
				this.speechRecognizerManager.OnError = (res) => {
					console.log(res);
					this.isCanSendData = false;
					this.recording = false;
					this.disabled = false
				};
				this.speechRecognizerManager.OnRecorderStop = () => {
					console.log('超过录音时长');
				};
			}
		},
		methods: {
			// 初始化音频事件
			initAudioEvent() {
				var that = this
				this.innerAudioContext = uni.createInnerAudioContext({
					useWebAudioImplement: true // 默认关闭。对于短音频、播放频繁的音频建议开启此选项
				});

				this.innerAudioContext.autoplay = true; // 自动播放
				// this.innerAudioContext.loop = true; // 自动播放
				// this.innerAudioContext.play(); // 手动播放

				this.innerAudioContext.onCanplay(() => {
					console.log('onCanplay')
				})
				this.innerAudioContext.onPlay(() => {
					console.log('音频开始播放');
					// uni.showLoading({
					// 	title: '播放中',
					// 	mask: true,
					// })
				});

				this.innerAudioContext.onPause(() => {
					console.log('音频暂停播放');
				});

				this.innerAudioContext.onStop(() => {
					console.log('音频停止播放');
				});
				this.innerAudioContext.onEnded(() => {
					console.log('onEnded')
					that.innerAudioContext.src = 'null.m4a'
					wx.hideLoading({
						success: (res) => {},
					})
				})

				this.innerAudioContext.onError((res) => {
					console.log(res.errMsg);
					console.log(res.errCode);
				});
			},

			pauseAudio() {
				this.innerAudioContext.pause(); // 手动播放
			},

			stopAudio() {
				this.innerAudioContext.stop(); // 手动播放
			},

			playAudio(type) {
				let currentTestInfo = {
					systemSuccessTip: 'https://cdn.spbcn.org/audio/lexicon/0/sky1.mp3'
				};
				let voiceUrl = '';
				if (type == 'error') {
					voiceUrl = currentTestInfo.systemErrorTip;
					uni.showLoading({
						title: '请处理答错逻辑',
						mask: true,
					})
				}
				if (type == 'success') {
					voiceUrl = currentTestInfo.systemSuccessTip;
					uni.showLoading({
						title: '请处理答对逻辑',
						mask: true,
					})
				}
				if (type == 'word') {
					voiceUrl = currentTestInfo.word_url;
				}
				if (type == 'part_of_speech') {
					voiceUrl = currentTestInfo.part_of_speech_url;
				}
				if (type == 'definition') {
					voiceUrl = currentTestInfo.definition_url;
				}
				if (type == 'sentence') {
					voiceUrl = currentTestInfo.sentence_url;
				}
				this.innerAudioContext.src = voiceUrl;
				// this.innerAudioContext.src = 'https://cdn.spbcn.org/audio/lexicon/0/sky1.mp3';
			},

			// 处理音频
			playAudio1() {
				uni.hideLoading()
				// uni.showLoading({
				// 	title: '请稍后',
				// 	mask: true,
				// })
				this.innerAudioContext.src = 'https://cdn.spbcn.org/audio/lexicon/0/sky1.mp3';
			},
			playAudio2() {
				uni.hideLoading()
				// uni.showLoading({
				// 	title: '请稍后1',
				// 	mask: true,
				// })
				this.innerAudioContext.src = 'https://cdn.spbcn.org/audio/lexicon/0/sky2.mp3';
			},
			playAudio3() {
				uni.hideLoading()
				// uni.showLoading({
				// 	title: '请稍后',
				// 	mask: true,
				// })
				this.innerAudioContext.src = 'https://cdn.spbcn.org/audio/lexicon/0/sky3.mp3';
			},

			startLy: async function(e) {
				const self = this;
				uni.getSetting({
					success(res) {
						if (!res.authSetting['scope.record']) {
							uni.authorize({
								scope: 'scope.record',
								success() {
									// 用户已经同意小程序使用录音功能，后续调用 record 接口不会弹窗询问
									self.startAsr();
								},
								fail() {
									uni.showToast({
										title: '未获取录音权限',
										icon: 'none'
									});
									// console.log("fail auth")
								}
							});
						} else {
							self.startAsr();
							// console.log("record has been authed")
						}
					},
					fail(res) {
						// console.log("fail",res)
					}
				});
			},
			startAsr: function() {
				uni.showToast({
					title: '建立连接中',
					icon: 'none'
				});
				resultText = '';
				let hotword_list = [
					"apple|10",
					"part of speech|10",
					"part|10",
					"of|10",
					"speech|10",
					"definition|10",
					"sentence|10"
				];
				const params = {
					// 用户参数
					secretkey: 'V2X3d8ulhirvtkVFtPygTJa0Nl6bCHVe',
					secretid: 'AKIDDYp3Nf0FR4vpeNzW9gK1oYSMCHONMKNB',
					appid: '1323065199', // 腾讯云账号appid（非微信appid）

					// 录音参数
					duration: 60 * 1000,
					// frameSize: 1.28,  //单位:k

					// 实时识别接口参数
					engine_model_type: '16k_en',
					// 以下为非必填参数，可跟据业务自行修改
					//公司帐号
					hotword_id: "7877d77dc4c311ee9e0c525400aec391", //热词
					customization_id: '948254e1c4c311eebe3c446a2eb5fd98', //自学习模型

					needvad: 1,
					// filter_dirty: 1,
					// filter_modal: 2,
					filter_punc: 0,
					// convert_num_mode : 1,
					word_info: 2,
					vad_silence_time: 200,
					hotword_list: hotword_list,
				};

				this.speechRecognizerManager.start(params);

				uni.vibrateShort();
			},
			endLy: function(e) {
				this.recording = false;
				this.disabled = false
				this.speechRecognizerManager.stop();
			},

			fnChecking() {
				this.fnCheckResult('my word is A P P L E okey', 'apple');
			},

			//核验结果
			fnCheckResult(resultText, keyword) {
				if (resultText.trim() !== '') {
					// 判断是否需要提示
					console.log('判断是否需要提示:----->', resultText)
					if (!this.checkIsNeedTips(resultText)) {
						this.renderTable(voice_id, resultText, true);

						var userAnswer = $fnTxvoice.getContentStr(keyword, this.tableList);
						var isRight = $fnTxvoice.getSpellStatus(keyword, userAnswer);
						//错
						if (isRight == -1) {
							//有拼写字母错语
							console.log('------------------拼写逻辑')
							// 拼写错误
							this.endLy();
							this.playAudio('error');
						}
						if (isRight == 0) {

						}
						//对
						if (isRight == 1) {
							//判断是否有单词读音
							if (this.isEnglishSentence(resultText)) {
								//拼写正确
								this.endLy();
								this.playAudio('success');
							}
						}
					} else {
						if ('判断是否有答案存在，如果没有答案，再提示') {
							var userAnswer = $fnTxvoice.getContentStr(keyword, this.tableList);
							var isRight = $fnTxvoice.getSpellStatus(keyword, userAnswer);
							//错
							if (isRight == -1) {
								this.renderTable(voice_id, resultText, true);
								//有拼写字母错语
								console.log('------------------拼写逻辑')
								// 拼写错误
								this.endLy();
								this.playAudio('error');
							}
							if (isRight == 0) {
								this.renderTable(voice_id, resultText, false);

								// 没有在拼写，肯定不是答案
								if (
									this.hasStrByType(resultText, 'word')
								) {
									console.log('word提示音始播放------------')
									this.endLy();
									this.playAudio('word');
								} else if (
									this.hasStrByType(resultText, 'part_of_speech')
								) {
									console.log('part_of_speech提示音始播放------------')
									this.endLy();
									this.playAudio('part_of_speech');
								} else if (
									this.hasStrByType(resultText, 'definition')
								) {
									console.log('definition提示音始播放------------')
									this.endLy();
									this.playAudio('definition');
								} else if (
									this.hasStrByType(resultText, 'sentence')
								) {
									console.log('sentence提示音始播放------------')
									this.endLy();
									this.playAudio('sentence');
								} else {

								}
							}
							//对
							if (isRight == 1) {
								this.renderTable(voice_id, resultText, true);

								if (this.isEnglishSentence(resultText)) {
									//拼写正确
									this.endLy();
									this.playAudio('success');
								}
							}
						}
					}
				}
			},

			//核验结果【简单：过滤错误的情况，仅当对的时候提示答题成功】
			fnCheckResultSimple(currentText, keyword) {
				if (currentText.trim() !== '') {
					var userAnswer = $fnTxvoice.getContentStr(keyword, [{
						'isAnswer': true,
						'content': currentText
					}, ...this.tableList]);
					var isRight = $fnTxvoice.getSpellStatus(keyword, userAnswer);
					// console.log('userAnswer:', userAnswer)
					// console.log('isRight:', isRight)
					//错
					if (isRight == -1) {

					}
					if (isRight == 0) {

					}
					//对
					if (isRight == 1) {
						// layer.msg('【简单检测-->】')
						//判断是否有单词读音
						if (this.isEnglishSentence(currentText)) {
							this.renderTable(voice_id, currentText, true);

							// console.log("【简单识别:V】")
							//拼写正确
							this.endLy();
							this.playAudio('success');
						}
					}
				}
			},

			//人工介入
			fnPeopleIn() {
				var currentTime = parseInt($('#test2').html());
				var timeIndex = layer.open({
					type: 1,
					title: '温馨提示：',
					area: ['95%', '100%'],
					shade: 1,
					scrollbar: false,
					time: currentTime * 1000,
					offset: 't',
					content: `
			                        <div>
			                            <div class="layui-row layui-col-space15" style="text-align: center;overflow: hidden">
			                                <div class="layui-col-sm3 layui-col-xs3">
			                                    <div class="layui-card">
			                                        <div class="layui-card-header">word</div>
			                                        <div class="layui-card-body layuiadmin-card-list">
			                                            <i test-active="play-video" type="word" class="layui-icon layui-icon-play" style="font-size: 38px; color: green;font-weight: bold;"></i>
			                                        </div>
			                                    </div>
			                                </div>
			                                <div class="layui-col-sm3 layui-col-xs3">
			                                    <div class="layui-card">
			                                        <div class="layui-card-header" style="word-break: break-all;">part of speech</div>
			                                        <div class="layui-card-body layuiadmin-card-list">
			                                            <i test-active="play-video" type="part_of_speech" class="layui-icon layui-icon-play" style="font-size: 38px; color: green;font-weight: bold;"></i>
			                                        </div>
			                                    </div>
			                                </div>
			                                <div class="layui-col-sm3 layui-col-xs3">
			                                    <div class="layui-card">
			                                        <div class="layui-card-header">definition</div>
			                                        <div class="layui-card-body layuiadmin-card-list">
			                                               <i test-active="play-video" type="definition" class="layui-icon layui-icon-play" style="font-size: 38px; color: green;font-weight: bold;"></i>
			                                        </div>
			                                    </div>
			                                </div>
			                                <div class="layui-col-sm3 layui-col-xs3">
			                                    <div class="layui-card">
			                                        <div class="layui-card-header">sentence</div>
			                                        <div class="layui-card-body layuiadmin-card-list">
			                                             <i test-active="play-video" type="sentence" class="layui-icon layui-icon-play" style="font-size: 38px; color: green;font-weight: bold;"></i>
			                                        </div>
			                                    </div>
			                                </div>
			                            </div>
			                        </div>
			                    `,
					btn: ['晋级', '淘汰'],
					btnAlign: 'c',
					yes: function() {
						layer.msg('晋级')
						parent.layui.$("#jinjiBtn" + currentTestInfo.playerId).trigger("click");
						layer.close(timeIndex);
					},
					btn2: function() {
						layer.msg('淘汰')
						parent.layui.$("#taotaiBtn" + currentTestInfo.playerId).trigger("click");
						layer.close(timeIndex);
					},
					zIndex: layer.zIndex, // 重点 1 --- 初始设置当前最高层叠顺序，
					success: function(layero, index) {
						layero.find(".layui-layer-content").css({
							"overflow": "hidden",
							"height": "200px",
						});

						layer.setTop(layero); // 重点 2 --- 保持选中窗口置顶
						var timeNum = this.time / 1000,
							setText = function(start) {
								layer.title('<span class="layui-font-red">' + (start ? timeNum : --timeNum) +
									'</span> 秒后自动关闭', index);
							};
						setText(!0);
						this.timer = setInterval(setText, 1000);
						if (timeNum <= 0) clearInterval(this.timer);
					},
					end: function() {
						clearInterval(this.timer);
						var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引
						parent.layer.close(index);
					}
				});
			},

			//判断是否需要提示
			checkIsNeedTips(content) {
				// var wordTip = ["pardon", "repeat", "again", "pronunciation", "word"];
				// var speechTip = ["part of speech", "part", "part speech", "part of", "of speech", "speech", "defeat", "Da"];
				// var definitionTip = ["definition", "define", "definite", "dolphin", "ing", "deafening", "defi"];
				// var sentenceTip = ["sentence", "certain", "Cent", "Heaven", "Part of which"];
				// var tipObj = {
				//     word: wordTip,
				//     part_of_speech: speechTip,
				//     definition: definitionTip,
				//     sentence: sentenceTip,
				// };

				//不需要提示
				if (!this.checkStringContainsAny(content, ["my word is", "the word is"])) {
					var newArr = [];
					var patterns = newArr.concat(tipObj.word, tipObj.part_of_speech, tipObj.definition, tipObj.sentence);

					console.log('checkIsNeedTips-------------------', content)
					content = content.trim().toLowerCase();
					content = content.split(',').join(' ')
					content = content.split('.').join(' ')
					content = content.split('?').join(' ')
					content = " " + content + " ";
					console.log('checkIsNeedTips-------------------', content)
					var count = 0;
					for (var i = 0; i < patterns.length; i++) {
						var item = patterns[i].trim().toLowerCase();
						if (content.includes(" " + item + " ")) {
							console.log('item:', item)
							count++;
						}
					}
					// console.log('count-----', count)
					if (count > 0) {
						return true;
					} else {
						return false;
					}
				} else {
					return false;
				}
			},

			renderTable(voice_id, content, isAnswer) {
				this.tableList.unshift({
					'id': this.tableList.length,
					'voice_id': voice_id ? voice_id : '测试',
					'content': content,
					'isAnswer': isAnswer
				})

				for (let i = 0; i < this.tableList.length; i++) {
					if (i == 0) {
						this.tableList[i].LAY_CHECKED = true;
					} else {
						this.tableList[i].LAY_CHECKED = false;
					}
				}
			},

			hasStrByType(str, type) {
				console.log('==================')
				console.log('hasWordStr:')
				str = str.toLowerCase();
				var keywords = tipObj[type];
				console.log('提示判断：start')
				console.log(str, type);
				console.log(keywords);
				console.log('提示判断：end')
				var count = 0;
				for (let i = 0; i < keywords.length; i++) {
					var item = keywords[i];
					item = item.toLowerCase();
					if (str.includes(item)) {
						count++;
					}
				}
				if (count > 0) {
					return true;
				} else {
					return false;
				}
			},

			//判断一个英文语句中是以英文单词开头或结尾
			isEnglishSentence(sentence) {
				console.log('isEnglishSentence = ', sentence)
				sentence = sentence.toLowerCase();

				// 定义特殊符号的正则表达式
				const specialCharsRegex = /[!@#$%^&*(),.?":{}|<>]/g;

				// 使用空字符串替换特殊符号
				sentence = sentence.replace(specialCharsRegex, " ").trim();

				// 定义英文单词的正则表达式
				const wordRegex = /^[A-Za-z]+$/;

				// 获取语句的第一个单词
				const firstWord = sentence.split(" ")[0];

				// 获取语句的最后一个单词
				const lastWord = sentence.split(" ").slice(-1)[0];

				var count = 0;
				if (firstWord.length > 1) {
					count++;
				}
				if (lastWord.length > 1) {
					count++;
				}

				console.log('firstWord=', firstWord)
				console.log('lastWord=', lastWord)

				// 判断第一个单词是否以英文单词开头
				const startsWithWord = wordRegex.test(firstWord);

				// 判断最后一个单词是否以英文单词结尾
				const endsWithWord = wordRegex.test(lastWord);

				const result = count > 0 && (startsWithWord || endsWithWord);

				console.log('result=', result)
				return result;
			},

			//js 判断字符串包含指定的多个字符串中的某一个就行
			checkStringContainsAny(str, substrings) {
				console.log("checkStringContainsAny", str, substrings)
				str = str.toLowerCase()
				return substrings.some(substring => str.includes(substring));
			},
		}
	}
</script>

<style>
	page {
		box-sizing: border-box;
	}

	.identify-text {
		padding: 30rpx;
		font-size: 32rpx;
		font-weight: 400;
		color: #000;
		text-align: center;
		margin: 30rpx 20px;
	}

	.identify-btn-media {
		background-color: #fff;
		padding-bottom: 200rpx;
		margin-left: -14rpx;
		width: 100%;
		bottom: 0;
		text-align: center;
	}

	.identify-btn-media .text {
		font-size: 28rpx;
		font-weight: 400;
		color: #999;
		margin-bottom: 36rpx;
	}

	.identify-btn-box {
		width: 100%;
		margin-bottom: 100rpx;
	}

	.identify-btn-box .loading {
		display: none;
		vertical-align: middle;
	}

	.identify-btn-box.active .loading {
		display: inline-block;
	}

	.identify-btn-box .loading>view {
		display: inline-block;
		vertical-align: middle;
		width: 8rpx;
		background-color: #006EFF;
		margin-right: 16rpx;
		border-radius: 50rpx;
	}

	.identify-btn-box .loading>view:last-child {
		margin-right: 0;
	}

	.line1 {
		animation: lines 0.5s infinite ease-in-out alternate;
	}

	.line2 {
		animation: lines 0.3s infinite ease-in-out alternate;
	}

	.line3 {
		animation: lines 0.4s infinite ease-in-out alternate;
	}

	.line4 {
		animation: lines 0.2s infinite ease-in-out alternate;
	}

	.line5 {
		animation: lines 0.6s infinite ease-in-out alternate;
	}

	@keyframes lines {

		from,
		10% {
			height: 4rpx;
		}

		to,
		90% {
			height: 40rpx;
		}
	}

	@-webkit-keyframes lines {

		from,
		10% {
			height: 4rpx;
		}

		to,
		90% {
			height: 40rpx;
		}
	}

	.identify-btn-box .btn-speak-media {
		width: 216rpx;
		height: 204rpx;
		display: inline-block;
		vertical-align: middle;
		background-image: url();
		background-size: cover;
		background-repeat: no-repeat;
		background-position: 50%;
	}

	.identify-btn-box.active .btn-speak-media {
		background-image: url();
	}

	.btn {
		border-radius: 5px;
		background-color: #006eff;
	}

	.tableHeader {
		display: flex;
		flex-direction: row;
	}
</style>